/*
基础库的封装
*/
#include<stdlib.h>
#include<string>
#include<netinet/in.h>
#include<sys/socket.h>
#include<unistd.h>
#include<fcntl.h>
#include<signal.h>
#include<netinet/tcp.h>
#include<cstring>
#include"log.h"
#include"util.h"        
const int BUFFSIZE = 4096;


void shutDownWR(int fd){
    shutdown(fd,SHUT_WR);
}

/*
处理SIGPIPE信号
连接双方的一个关闭连接, 另一个仍然向他写数据时
第一个写数据会收到RST响应
第二次写时内核向进程发出SIGPIPE信号, 内核对信号的处理默认是终止程序,handler_for_sigpipe用来忽略该信号
*/
void handler_for_sigpipe(){
    struct sigaction sa;
    memset(&sa,'\0',sizeof(sa));
    sa.sa_handler=SIG_IGN;
    sa.sa_flags=0;
    if(sigaction(SIGPIPE,&sa,NULL)){
        return;
    }
}

//一条龙服务
int socket_bind_listen(int port){
    if(port<0 || port>65535) return -1;
    int listenfd=0;
    if((listenfd=socket(AF_INET,SOCK_STREAM,0))<0){
        record(Level::Error)<<"socket listenfd error";
        return -1;
    }
    int optval=1;
    if(setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))<0){
        close(listenfd);
        record(Level::Error)<<"set listenfd reuse error";
        return -1;
    }
    sockaddr_in servaddr;
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(port);
    servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    if(bind(listenfd,(sockaddr*)&servaddr,sizeof(servaddr))<0){
        close(listenfd);
        record(Level::Error)<<"bind listenfd error";
        return -1;
    }
    if(listen(listenfd,2048)<0){
        close(listenfd);
        record(Level::Error)<<"listen error";
        return -1;
    }
    return listenfd;
}

//设置套接字为非阻塞
int setNonBlocking(int fd){
    int flag=fcntl(fd,F_GETFL,0);
    if(flag<0){
        record()<<"when setNonBlocking, flag of fd is <0";
        return -1;
    }
    flag |= O_NONBLOCK;
    if(fcntl(fd,F_SETFL,flag)<0){
        record()<<"when setNonBlocking, fcntl return error";
        return -1;
    }
    return 0;
}

//TCP_NODELAY是针对tcp套接字专用的选项, 用来禁止nagle算法
//nagle算法:将小分组组成大分组, 可能导致包发送不实时
void setNodelay(int fd){
    int enable = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&enable, sizeof(enable));
}

ssize_t readn(int fd,void *buff, size_t n){
    size_t nleft = n;
    ssize_t nread = 0;
    ssize_t readSum = 0;
    char *ptr=(char*)buff;
    while(nleft>0){
        if((nread=read(fd,ptr,nleft))<0){
            if(errno==EINTR){
                nread=0;
                record()<<"when read, EINTR happen";
            }
            else if(errno == EAGAIN){
                return readSum;
            }
            else{
                record()<<"when read, something error";
                return -1;
            }
        }
        else if(nread==0){
            break;
        }
        readSum+=nread;
        nleft-=nread;
        ptr+=nread;
    }
    return readSum;
}

ssize_t readn(int fd,std::string &inBuffer, bool &zero){
    ssize_t nread = 0;
    ssize_t readSum = 0;
    while (true) {
        char buf[BUFFSIZE];
        nread = 0;
        if ((nread = read(fd, buf, BUFFSIZE)) < 0) {
            if(errno == EINTR)//EINTR error
                continue;
            else if (errno == EAGAIN) //EAGAIN error
            {
                return readSum;
            } else //real error
            {
                record()<<"readn error";
                return -1;
            }
        } else if (nread == 0)//end
        {
            zero = true;
            record()<<"zero is true";
            break;
        }
        readSum += nread;
        inBuffer += std::string(buf,nread);
    }
    return readSum;
}

ssize_t readn(int fd,std::string &inBuffer){
    bool zero = false;
    return readn(fd,inBuffer,zero);
}

ssize_t writen(int fd, void *buff, size_t n){
    ssize_t nleft = n;
    //write返回值
    ssize_t nwrite = 0;
    //已经写了的数据总和
    ssize_t nwsum = 0;
    char *ptr = static_cast<char*>(buff);
    while(nleft>0){
        if((nwrite = write(fd,ptr,nleft))<=0){
            if(nwrite<0){
                //write系统调用被中断
                if(errno==EINTR){
                    nwrite=0;
                    continue;
                }
                //发送缓冲区满了
                else if(errno == EAGAIN){   
                    return nwsum;    
                }
                else{
                    record()<<"writeen error";
                    return -1;
                }
            }
        }
        nleft -= nwrite;
        nwsum += nwrite;
        ptr += nwrite;
    }
    return nwsum;
}

ssize_t writen(int fd, std::string &sbuff){
    record()<<"开始发送数据";
    ssize_t nleft = sbuff.size();
    ssize_t nwritten = 0;
    ssize_t writeSum = 0;
    const char *ptr = sbuff.c_str();
    while(nleft>0){
        if((nwritten = write(fd, ptr, nleft) )< 0){
            if(errno == EINTR) {
                nwritten = 0;
                continue;
            } else if (errno == EAGAIN)
                break;
            else{
                record()<<"writeen error";
                return -1;
            }
        }
        writeSum += nwritten;
        nleft -= nwritten;
        ptr += nwritten;
    }
    if(writeSum == static_cast<int>(sbuff.size())){
        sbuff.clear();
    }
    else{
        sbuff=sbuff.substr(writeSum);
    }
    return writeSum;
}